package cn.leftsite.netty.test.codec;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageCodec;
import io.netty.handler.codec.http.websocketx.*;

import java.util.List;

/**
 * @author wangjinqiang
 * @date 2019-05-30
 */
public class WebSocketConvertHandler extends MessageToMessageCodec<WebSocketFrame, WebSocketConvertHandler.MyWebsocketFrame> {

    /**
     * 将MyWebSocketFrame 编码为指定的WebSocketFrame子类型
     */
    @Override
    protected void encode(ChannelHandlerContext ctx, MyWebsocketFrame msg, List<Object> out) throws Exception {
        ByteBuf payload = msg.getData().duplicate().retain();
        // 实例化一个指定子类型的WebSocketFrame
        switch (msg.getFrameType()) {
            case BINARY:
                out.add(new BinaryWebSocketFrame(payload));
                break;
            case TEXT:
                out.add(new TextWebSocketFrame(payload));
                break;
            case PING:
                out.add(new PingWebSocketFrame(payload));
                break;
            case PONG:
                out.add(new PongWebSocketFrame(payload));
                break;
            case CLOSE:
                out.add(new CloseWebSocketFrame(true, 0, payload));
                break;
            case CONTINUATION:
                out.add(new ContinuationWebSocketFrame(payload));
                break;
            default:
                throw new IllegalStateException("Unsupported websocket msg " + msg);
        }

    }

    /**
     * 将WebSocketFrame 解码为MyWebSocketFrame，并设置FrameType
     */
    @Override
    protected void decode(ChannelHandlerContext ctx, WebSocketFrame msg, List<Object> out) throws Exception {
        ByteBuf payload = msg.content().duplicate().retain();

        if (msg instanceof BinaryWebSocketFrame) {
            out.add(new MyWebsocketFrame(MyWebsocketFrame.FrameType.BINARY, payload));
        } else if (msg instanceof CloseWebSocketFrame) {
            out.add(new MyWebsocketFrame(MyWebsocketFrame.FrameType.CLOSE, payload));
        } else if (msg instanceof PingWebSocketFrame) {
            out.add(new MyWebsocketFrame(MyWebsocketFrame.FrameType.PING, payload));
        } else if (msg instanceof PongWebSocketFrame) {
            out.add(new MyWebsocketFrame(MyWebsocketFrame.FrameType.PONG, payload));
        } else if (msg instanceof TextWebSocketFrame) {
            out.add(new MyWebsocketFrame(MyWebsocketFrame.FrameType.TEXT, payload));
        } else if (msg instanceof ContinuationWebSocketFrame) {
            out.add(new MyWebsocketFrame(MyWebsocketFrame.FrameType.CONTINUATION, payload));
        } else {
            throw new IllegalStateException("Unsupported websocket msg " + msg);
        }
    }

    /**
     * 声明WebSocketConvertHandler所使用的OUTBOUND_IN 类型
     */
    public static final class MyWebsocketFrame {
        public enum FrameType {
            BINARY,
            CLOSE,
            PING,
            PONG,
            TEXT,
            CONTINUATION
        }

        private final FrameType frameType;

        private final ByteBuf data;

        public MyWebsocketFrame(FrameType frameType, ByteBuf data) {
            this.frameType = frameType;
            this.data = data;
        }

        public FrameType getFrameType() {
            return frameType;
        }

        public ByteBuf getData() {
            return data;
        }
    }
}
